Lok Sabha 2019 Choropleth (MPs assets)

Interactive Choropleth using Plotly

Map sourced from Datameet maps

Data sourced from myneta

In [1]:
import json
import numpy as np
import pandas as pd
from matplotlib.colors import Normalize
from matplotlib import cm
from itertools import product
import copy

from plotly.offline import init_notebook_mode, iplot
init_notebook_mode(connected=True)
import plotly.plotly as ply
from collections import defaultdict

MAPBOX_APIKEY = "Your Mapbox key"

Load the geojson

In [2]:
with open('merged_2019_pc_map_1pc_trim.json') as f:
     geojson = json.load(f)

Count the number of parliamentary constituencies

In [3]:
# Print a sample of properties in geojson file
 [geojson['features'][1]['properties']]
Out[3]:
[{'ST_NAME_x': 'HIMACHAL PRADESH',
  'PC_NAME_x': 'MANDI',
  'Age': 60,
  'Candidate': 'Ram Swaroop Sharma',
  'Criminal_C': 0,
  'Education': '10th Pass',
  'Party': 'BJP',
  'Winner': 'Yes',
  'Year': 2019,
  'Liabilitie': 783963,
  'Assets_num': 15724337}]
In [4]:
# Get number of PCs
n_pc = len(geojson['features'])

print("there are {} PCs ".format(n_pc))
there are 543 PCs 

Center of each province

In [5]:
def get_centers():
    lon, lat =[], []

    for k in range(n_pc):
        geometry = geojson['features'][k]['geometry']

        if geometry['type'] == 'Polygon':
            coords=np.array(geometry['coordinates'][0])
        elif geometry['type'] == 'MultiPolygon':
            coords=np.array(geometry['coordinates'][0][0])

        lon.append(sum(coords[:,0]) / len(coords[:,0]))
        lat.append(sum(coords[:,1]) / len(coords[:,1]))
            
    return lon, lat

Make the sources:

In [6]:
def make_sources():
    sources = []
    geojson_copy = copy.deepcopy(geojson['features'])
    
    for feature in geojson_copy:            
        sources.append(dict(type = 'FeatureCollection', 
                            features = [feature])
                      )
    return sources

Define the colours, the colorscale and the hover text

In [7]:
# create list of tuples having touple format (PC_NAME_x, Criminal_C)
pc_list = [geojson['features'][k]['properties']['PC_NAME_x']  for k in range(n_pc)]

asset_list = [geojson['features'][k]['properties']['Assets_num'] for k in range(n_pc)]

mp_list =  [geojson['features'][k]['properties']['Candidate'] for k in range(n_pc)]

pc_asset_dict = dict(PC_NAME = pc_list, Assets_num = asset_list, Candidate = mp_list)
In [8]:
# pc_crime_dict
In [9]:
#  Create dataframe from list of touples 
pc_asset_df = pd.DataFrame(pc_asset_dict)
In [10]:
pc_asset_df.head()
Out[10]:
PC_NAME Assets_num Candidate
0 KANGRA 85841247.0 Kishan Kapoor
1 MANDI 15724337.0 Ram Swaroop Sharma
2 HAMIRPUR 56770463.0 Anurag Singh Thakur
3 SHIMLA 15705738.0 Suresh Kumar Kashyap
4 GURDASPUR 871925679.0 Ajay Singh Dharmendra Deol (Sunny Deol)
In [11]:
# find the NaNs in the df
# pc_crime_df[pc_crime_df['CriminalC'].isna()]
In [12]:
def scalarmappable(cmap, cmin, cmax):
        colormap = cm.get_cmap(cmap)       
        norm = Normalize(vmin=cmin, vmax=cmax)
        print(norm)
        return cm.ScalarMappable(norm=norm, cmap=colormap)
    
def get_scatter_colors(sm, df):
    grey = 'rgba(0, 0,128,0.6)'
    return ['rgba' + str(sm.to_rgba(m, bytes = True, alpha = 1)) if not np.isnan(m) else grey for m in df['Assets_num']]

def get_colorscale(sm, df, cmin, cmax):
    xrange = np.linspace(0, 1, len(df))
    values = np.linspace(cmin, cmax, len(df))

    return [[i, 'rgba' + str(sm.to_rgba(v, bytes = True))] for i,v in zip(xrange, values) ]
 
def get_hover_text(df) :
   # convert array of int to array of string
    text_value = [int(x) if not np.isnan(x) else 0 for x in df.Assets_num]
    
    with_data = '<b>Constituency: {}</b> <br><b>Candidate: {}</b><br><b>Assets(Rs): {:,}</b>'
    no_data = '<b>{}</b> <br> no data'
    
    return [with_data.format(p,v, q) if v else no_data.format(p) for p,v,q in zip(df.PC_NAME, df.Candidate, text_value)]

Ready to make map

In [13]:
colormap = 'YlGn'

cmin = min(pc_asset_df.Assets_num)
cmax = max(pc_asset_df.Assets_num)

sources = make_sources()
lons, lats = get_centers()

sm = scalarmappable(colormap, cmin, cmax)
scatter_colors = get_scatter_colors(sm, pc_asset_df)
colorscale = get_colorscale(sm, pc_asset_df, cmin, cmax)
hover_text = get_hover_text(pc_asset_df)

tickformat = ",d"
<matplotlib.colors.Normalize object at 0x7f8447bc3128>

The scattermapbox data

In [14]:
data = dict(type='scattermapbox',
             lat=lats,
             lon=lons,
             mode='markers',
             text=hover_text,
             marker=dict(size=1,
                         color=scatter_colors,
                         showscale = True,
                         cmin = cmin,
                         cmax = cmax,
                         colorscale = colorscale,
                         colorbar=dict(tickformat=tickformat, 
#                                       tickprefix= "Rs. ",
                                      title="Assets (In Rs.)",
                                      titlefont = dict(size=14,
                                                       family='Arial, sans-serif'
                                                       ),
                                      titleside='right'
                                      )
                         ),
             showlegend=False,
             hoverinfo='text'
             )

The borders

In [15]:
layers=([dict(sourcetype = 'geojson',
        source =sources[k],
        below="",
        type = 'line',
        line = dict(width = 0.1),
        color = 'black',
        ) for k in range(n_pc)] +

        [dict(sourcetype = 'geojson',
             source =sources[k],
             below="water",
             type = 'fill',
             color = scatter_colors[k],
             opacity=0.8
            ) for k in range(n_pc)]
        )

The layout

In [16]:
layout = dict(title="Assets of MPs elected in LokSabha Election (2019) <br> " +
                    """using data from http://www.myneta.info""",
      autosize=False,
      width=880, #700,
      height=930, #800
      hovermode='closest',
      hoverdistance = 30,

      mapbox=dict(accesstoken=MAPBOX_APIKEY,
                  layers=layers,
                  bearing=0,
                  center=dict(
                  lat=23,
                  lon=82.5),
                  pitch=0,
                  zoom=4,
                  style = 'light'
            )
      )
In [17]:
fig = dict(data=[data], layout=layout)
iplot(fig)